package com.googlecode.spoluyan.myshows;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.google.gson.Gson;

public class Utils {
    private static final Gson GSON = new Gson();

    public static boolean isEmptyString(String string) {
	return (string == null || string.trim().length() == 0);
    }

    public static void closeQuietly(Closeable closeable) {
	try {
	    if (closeable != null) {
		closeable.close();
	    }
	} catch (IOException ioe) {
	}
    }

    public static String doRequest(Set<String> cookies, Map<String, String> queryParams, String... restParams)
	    throws UnsupportedEncodingException {
	return getResponseAsString(cookies, generateURL(queryParams, restParams));
    }

    public static String generateURL(Map<String, String> queryParams, String... restParams)
	    throws UnsupportedEncodingException {
	StringBuilder sb = new StringBuilder(Defines.API_URL);
	for (String p : restParams) {
	    sb.append(p);
	}

	if (queryParams != null) {
	    sb.append(Defines.QUESTION_MARK);
	    for (String p : queryParams.keySet()) {
		String value = URLEncoder.encode(queryParams.get(p), Defines.ENCODING);
		sb.append(p).append(Defines.EQUALS_SIGN).append(value).append(Defines.AMPERSAND);
	    }
	    sb.deleteCharAt(sb.length() - 1);
	}
	return sb.toString();
    }

    public static byte[] getDataFromURL(Set<String> cookies, String urlString) {
	try {
	    URL url = new URL(urlString);
	    URLConnection conn = url.openConnection();

	    conn.setRequestProperty(Defines.COOKIE, getCookieString(cookies));
	    conn.connect();

	    return getDataFromOpenedConnection(conn);
	} catch (Exception e) {
	}
	return null;
    }

    public static byte[] getDataFromOpenedConnection(URLConnection conn) {
	InputStream in = null;
	ByteArrayOutputStream out = null;
	byte[] data = null;
	try {
	    in = conn.getInputStream();
	    out = new ByteArrayOutputStream();

	    byte[] byteChunk = new byte[4096];
	    int n;

	    while ((n = in.read(byteChunk)) > 0) {
		out.write(byteChunk, 0, n);
	    }

	    data = out.toByteArray();

	    out.close();
	    in.close();

	    return data;
	} catch (Exception e) {
	} finally {
	    closeQuietly(out);
	    closeQuietly(in);
	}
	return data;
    }

    public static String getResponseAsString(Set<String> cookies, String urlString) throws UnsupportedEncodingException {
	byte[] data = getDataFromURL(cookies, urlString);
	if (data == null) {
	    return null;
	}
	return new String(data, Defines.ENCODING);
    }

    private static String getCookieString(Set<String> cookies) {
	StringBuilder sb = new StringBuilder(Defines.EMPTY_STRING);
	for (String cookie : cookies) {
	    sb.append(cookie).append(Defines.SEMICOLON);
	}
	return sb.toString();
    }

    public static String getMD5(String string) throws NoSuchAlgorithmException, UnsupportedEncodingException {
	MessageDigest m = MessageDigest.getInstance(Defines.ENCODING_ALG);
	m.reset();
	m.update(string.getBytes(Defines.ENCODING));

	byte[] digest = m.digest();
	BigInteger bigInt = new BigInteger(1, digest);
	String hashtext = bigInt.toString(16);
	while (hashtext.length() < 32) {
	    hashtext = Defines.ZERO + hashtext;
	}

	return hashtext;
    }

    @SuppressWarnings("unchecked")
    public static <T> T fromJSON(String json, Type type) {
	// see bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954
	return (T) GSON.fromJson(json, type);
    }

    public static <T> T fromJSON(String json, Class<T> clazz) {
	return (T) GSON.fromJson(json, clazz);
    }

    public static <T> Set<T> setFromJSON(String json, Type type) {
	if (!isEmptyString(json)) {
	    Map<String, T> map = fromJSON(json, type);

	    Set<T> result = new HashSet<T>();
	    for (String key : map.keySet()) {
		result.add(map.get(key));
	    }
	    return result;
	}
	return Collections.emptySet();
    }

    public static String toJSON(Object obj) {
	return GSON.toJson(obj);
    }

    public static String longArrayToParamString(Long[] array) {
	if (array == null || array.length == 0) {
	    return Defines.EMPTY_STRING;
	}
	StringBuilder sb = new StringBuilder(Defines.EMPTY_STRING);
	for (Long l : array) {
	    sb.append(l.longValue()).append(Defines.COMMA);
	}
	sb.deleteCharAt(sb.length() - 1);
	return sb.toString();
    }

    public static Set<Long> jsonStringArrayToLongSet(String json) {
	if (!isEmptyString(json)) {
	    Set<Long> result = new HashSet<Long>();
	    String[] ids = Utils.fromJSON(json, String[].class);
	    for (String id : ids) {
		result.add(Long.valueOf(id));
	    }
	    return result;
	}
	return Collections.emptySet();
    }
}
